# codding = utf-8
import asyncio
import json
import os
import time

import cv2
import easydict
import websockets
from websockets.exceptions import ConnectionClosedOK

import cjc.project_setting
from cjc import project_setting
from cjc.tools.logger import Logger
from cjc.webapi.weather import parse_weather
from cjc.tools.cv2_base64 import base64_to_cv2_image
from cjc.ws_server.data_cache import msg_queue, get_webapi_msg_from_queue, set_q, put_message_to_queue, \
    get_data_from_queue, put_webapi_msg_to_queue
from cjc.ws_server.handle_client_msg import ClientMsgHandler
from cjc.ws_server.tools import app_heartbeat_code, create_msg_to_client, create_heartbeat_msg


class WebSocketClient:

    def __init__(self, can_track, addr="127.0.0.1:9000/back_client/yolo", overtime=5):
        self.IP_ADDR = addr
        self.ws = None
        self.msg_handler = ClientMsgHandler(can_track)
        self.last_update = time.time()
        self.overtime = overtime
        self.can_track = can_track
        self.last_video_path = None
        self.log=Logger(__class__.__name__)

    async def check_online(self):
        while True:
            await asyncio.sleep(0)
            # print("检查函数check_online", time.time() - self.last_update )
            if time.time() - self.last_update > self.overtime:
                self.log.info("超时重新链接")
                try:
                    self.ws = await websockets.connect("ws://" + self.IP_ADDR)
                    self.last_update = time.time()
                except ConnectionRefusedError:
                    self.last_update = time.time()

    async def run_recv(self):

        while True:
            await asyncio.sleep(0)
            if self.ws is None:
                continue
            try:
                response_str = await self.ws.recv()
                e = json.loads(response_str)
                recv_dic = easydict.EasyDict(e)
                self.last_update = time.time()
                if recv_dic.code == app_heartbeat_code:
                    pass
                else:
                    await self.msg_handler.handle(recv_dic)
            except:
                # print(e)
                pass

    async def run_send(self):

        while True:
            await asyncio.sleep(0)
            if self.ws is None:
                continue
            try:
                if not msg_queue.empty():
                    msg = await msg_queue.get()
                    await self.ws.send(msg)
            except ConnectionClosedOK as e:
                pass
            except:
                pass
                # print(e)

    async def create_message(self):
        project_setting.weather, project_setting.temperature = parse_weather()
        self.log.info(project_setting.weather, project_setting.temperature)
        while True:
            await asyncio.sleep(0.1)
            mp = await get_data_from_queue()
            if mp:
                if self.last_video_path is None and mp.video_path is not None:  # 初始化先保存本地路径
                    self.last_video_path = mp.video_path
                if mp.video_path is not None and mp.video_path != self.last_video_path:  # 消息有路径，并且路径和本地存储的不一样
                    await put_webapi_msg_to_queue(self.last_video_path, mp)
                    self.last_video_path = mp.video_path
                else:
                    msg = create_msg_to_client(mp)
                    await put_message_to_queue(msg)
                    #有消息也得创建心跳，简化逻辑防止掉线
                    msg = create_heartbeat_msg()
                    await put_message_to_queue(msg)
            else:
                await asyncio.sleep(1)
                # print("吸入心跳",time.localtime().tm_sec % (self.overtime/2) )
                msg = create_heartbeat_msg()
                await put_message_to_queue(msg)

    async def upload_record(self):
        print("启动 文件上传服务")

        while True:
            await asyncio.sleep(0)
            api_msg = await get_webapi_msg_from_queue()
            if api_msg is None:
                continue
            else:
                await self.msg_handler.upload_video_record(api_msg)


def processor_run_ws_server(track_queue, can_track):
    print("启动 websocket 客户端")
    w = WebSocketClient(can_track,overtime=project_setting.websocket_overtime)
    if track_queue is not None:
        set_q(track_queue)
    co = asyncio.gather(w.run_send(), w.run_recv(), w.check_online(), w.create_message(), w.upload_record())  # ,
    try:
        asyncio.get_event_loop().run_until_complete(co)
        asyncio.get_event_loop().run_forever()
    except KeyboardInterrupt:
        print("手工退出")


if __name__ == '__main__':
    processor_run_ws_server(None, None)
